
import wx
import sys
import threading
from socket import *

#Event ID
ID_EXIT = 200

#ID's sent to server to differentiate difference in sent messages
#Made them long so that the chance they'll be accidentally entered is very low
ID_CONNECT  = 300
ID_EXIT     = 400
ID_CHAT     = 500


#LAYOUT:
#    MainCotrolSizer (Vertical):
#        contains topSizer and bottomSizer
#    ---------------------------------
#    |                        |      |
#    |                        |      |
#    |                        |      |
#    |    topSizer(horizontal)|      |
#    |                        |      |
#    |                        |      |
#    |                        |      |
#    |                        |      |
#    |                        |      |
#    |                        |      |
#    |                        |      |
#    |                        |      |
#    |--------------------------------
#    |                               |
#    |     bottomSizer(horizontal    |
#    |                               |
#    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


class ChatGUI(wx.Frame):
    #Constructor
    def __init__(self):
        wx.Frame.__init__(self, None, title = "Chat")
        self.panel = wx.Panel(self)
        self.chatthread = ChatThread(self, "John")
        self.chatthread.start()
        self.chatthread.connect()
        
##---------Create Sizers-----------------

        mainContainerSizer = wx.BoxSizer(wx.VERTICAL)
        topSizer = wx.BoxSizer(wx.HORIZONTAL)
        bottomSizer = wx.BoxSizer(wx.HORIZONTAL)
        
        
##---------Create Widgets--------------
        
        #Buttons
        sendButton = wx.Button(self.panel,wx.ID_ANY, 'Send')
        
        
        #Text Boxes
        self.chatPane = wx.TextCtrl(self.panel,wx.ID_ANY,  style=wx.TE_MULTILINE)
        self.sendBox = wx.TextCtrl(self.panel, wx.ID_ANY, size = (200,20), style = wx.TE_PROCESS_ENTER)
        
        #Lists
        self.userList = wx.ListBox(self.panel, wx.ID_ANY)
        
        #SAMPLE USERS REMOVE LATER
        #These will have to be parsed and sent back
        #by the server using clientID's
   #     self.userList.Append("Sample User1")
   #     self.userList.Append("Sample User2")
   #     self.userList.Append("Sample User3"
   #     self.userList.Append("Sample User4")
      
        
        #Menus
        filemenu = wx.Menu()
        exit = wx.MenuItem(filemenu, ID_EXIT, 'E&xit')
        filemenu.AppendItem(exit)
        
        
        #MenuBar
        menuBar = wx.MenuBar()
        menuBar.Append(filemenu, "&File")        
        self.SetMenuBar(menuBar)
        
        
##---------Event Binding--------------

        #Button Event Bindings
        sendButton.Bind(wx.EVT_BUTTON, self.send)
        
        #TextBox Event Binding
        self.sendBox.Bind(wx.EVT_TEXT_ENTER, self.send)
        
        #Menu Event Binding
        self.Bind(wx.EVT_MENU, self.exitMenuAction, exit, id=ID_EXIT)
        
        
##---------Configure/Construct Sizers-------------
        
        bottomSizer.Add(self.sendBox, 1, wx.ALL, border = 5)
        bottomSizer.Add(sendButton, 0, wx.ALL, border = 5)
        topSizer.Add(self.chatPane, 1, wx.EXPAND)
        topSizer.Add(self.userList, 0, wx.EXPAND )
        mainContainerSizer.Add(topSizer, 1,  wx.EXPAND, border = 4)
        mainContainerSizer.Add(bottomSizer, 0, wx.EXPAND, border = 4)
                
        
##---------Configure Frame-------------
        self.panel.SetSizer(mainContainerSizer)
        mainContainerSizer.Fit(self)
        self.SetSize((500,500))       
     
        

##---------Bound Event Methods-------------

    def send(self, event):     
        self.chatthread.sendData(str(self.sendBox.GetValue() +"\n"))
        self.sendBox.SetValue("")
        
    

    def exitMenuAction(self, event):
        e = event.GetId()
        if e == ID_EXIT:
            sys.exit()

        
    def addChat(self, chatstring):
        self.chatPane.AppendText(chatstring)
          

    def addUser(self, user):
       userArray = user.split(",") 
       for u in userArray:
           self.userList.Append(u)
 
#Right now this class doesnt actually use any of the threading stuff
#It is just used to create a connection to the chat server
#Later on we'll have to ues threading so that each client
#can listen to the server for other people chatting 
class ChatThread(threading.Thread):
    def __init__(self, guiref, username):
        threading.Thread.__init__(self)
    
        # Set the socket parameters
        self.host = "localhost"
        self.port = 21567
        self.buf = 1024
        self.addr = (self.host,self.port)
        
        # Create socket
        self.UDPSock = socket(AF_INET,SOCK_DGRAM)
        
        #Set reference to the chatgui
        self.chat = guiref
        self.username = username
      
        
    def sendData(self, datastream):
        if not datastream:
                self.UDPSock.sendto(datastream, self.addr)
                print "You have exited"                
            
        else:                
            if(self.UDPSock.sendto(str(ID_CHAT)+datastream, self.addr)):                
                self.chat.addChat(self.username + ": "+ datastream)
                data,addr = self.UDPSock.recvfrom(self.buf)
                self.chat.addUser(data)
                
    def connect(self):
        self.UDPSock.sendto(str(ID_CONNECT)+self.username, self.addr)
        
                
                
#We'll need to override run later so that we actually have a thread
#Each client will also have to be a server   
#    def run(self):
#        while (self.stopped):
#            data = str(self.clientID) + raw_input('>> ')
#            self.sendData(data)    
#        pass            
          

        

               
        
# Run the program and set it to visible
if __name__ == '__main__':
    app = wx.PySimpleApp()
    frame = ChatGUI().Show()
    app.MainLoop()        
